import * as prettier from "prettier";
import * as _ from "lodash";

export const toLuaObject = (obj: any, padding = 0, tab = "    ", trailingComma = true) => {
  const pad = tab.repeat(padding),
    padn1 = padding > 0 ? tab.repeat(padding - 1) : "";
  if (typeof obj === "object" && obj !== null) {
    if (Array.isArray(obj)) {
      const isComplex = obj.some(v => typeof v === "object");
      const isLarge = isComplex ? obj.length > 3 : obj.length > 10;
      if (isLarge) {
        // multi-line array
        const raw = isComplex
          ? obj.map(v => toLuaObject(v, padding + 1)).join(`,\n${pad}`)
          : // 简单对象长数组使用每10个换一行
          _.chunk(obj, 10)
            .map(sub => {
              return sub.map(v => toLuaObject(v, padding + 1)).join(`, `);
            })
            .join(`,\n${pad}`);
        return `{\n${pad}${raw}${trailingComma ? "," : ""}\n${padn1}}`;
      } else {
        // single-line array
        const raw = obj.map(v => toLuaObject(v, padding)).join(", ");
        return "{" + raw + "}";
      }
    } else {
      const arr = _.filter(obj, v => v !== null);
      const isComplex = arr.length > 2 || arr.some(v => typeof v === "object");
      const content = _.map(obj, (v, k) => {
        if (v === null) return null;
        if (k.match(/^\w[\d\w]*$/)) return `${k} = ${toLuaObject(v, padding + 1)}`;
        else return `["${k}"] = ${toLuaObject(v)}`;
      }).filter(v => v !== null);
      if (isComplex) {
        // multi-line object
        return `{\n${pad}${content.join(",\n" + pad)}${trailingComma ? "," : ""}\n${padn1}}`;
      } else {
        // single-line object
        return `{ ${content.join(", ")} }`;
      }
    }
  }
  return JSON.stringify(obj);
};

export const convertObjectToLua = (arr: { name: string }[] | { [x: string]: any }, name: string, dataname = (name.endsWith("ies") ? name.substr(0, name.length - 3) + "y" : name.endsWith("s") ? name.substr(0, name.length - 1) : name) + "Data") => {
  const list = Array.isArray(arr) ? arr.map(c => `["${c.name}"] = ${toLuaObject(c, 2)}`) : _.map(arr, (v, k) => `["${k}"] = ${toLuaObject(v, 2)}`);
  const tmpl = `-- DATA

local ${dataname} = {
["${name}"] = {
    ${list.join(",\n    ")}
},
}
return ${dataname}`;
  return tmpl;
};

// MAP+索引形式
export const convertObjectToLuaV2 = (arr: { name: string }[], name: string, dataname = (name.endsWith("ies") ? name.substr(0, name.length - 3) + "y" : name.endsWith("s") ? name.substr(0, name.length - 1) : name) + "Data") => {
  const index = arr.map(c => `${toLuaObject(c.name, 3)}`);
  const list = arr.map(c => `["${c.name}"] = ${toLuaObject(c, 3)}`);
  const tmpl = `-- AUTOMATIC GENERATED, DO NOT EDIT
-- format: IndexedArray
-- see https://github.com/pa001024/arks

local ${dataname} = {
    ["${name}Index"] = {
        ${index.join(",\n        ")}
    },
    ["${name}"] = {
        ${list.join(",\n        ")}
    },
}
return ${dataname}`;
  return tmpl;
};

export const formatJSON = (src: any) => {
  return prettier.format(typeof src === "string" ? src : JSON.stringify(src), { parser: "json" });
};

export const isEmpty = (obj: object) => {
  if (Array.isArray(obj)) return obj.every(v => isEmpty(v));
  return !obj || (typeof obj === "object" && !Object.keys(obj).length);
};

export const firstCase = (src: string) => {
  return src[0].toUpperCase() + src.substr(1);
};

export const purge = <T>(a: T, filter = (v: unknown, i: string) => v !== 0 && !v) => {
  Object.keys(a).forEach(v => filter(a[v], v) && delete a[v]);
  return a;
};

/** JSON转换为WikiTab格式 */
export const json2Tab = (json: any[], title = "自动管理模板v1.0") => {
  const schema = {} as any;
  const data = json.map(line => {
    return _.map(line, (cell, key) => {
      if (!schema[key]) {
        schema[key] = {
          name: key,
          type: typeof cell,
          title: {
            en: key,
          },
        };
      }
      return cell;
    });
  });
  const tpl = {
    license: "CC0-1.0",
    description: {
      en: title,
    },
    sources: "AUTOMATIC GENERATED BY https://github.com/pa001024/arks",
    schema: {
      fields: _.map(schema),
    },
    data,
  };
  return tpl;
};

import async from "async";

export const forEachLimit = <T>(itor: T[], limit = 5, func: (t: T) => Promise<void>) => {
  return new Promise(resolve => {
    async.forEachLimit(itor, limit, func, err => {
      resolve(null);
    });
  });
};

import { promisify } from "util";
export const imgSizeOf: (file: string) => Promise<{ width: number; height: number }> = promisify(require("image-size"));

export const removeNull = (obj: any) => {
  if (typeof obj === "object") {
    if (Array.isArray(obj)) {
      return obj.filter(v => v !== null).map(v => removeNull(v));
    } else {
      const m = _.mapValues(obj, v => {
        if (v && typeof v === "object") return removeNull(v);
        return v;
      });
      _.forEach(m, (v, k) => {
        if (v === null) delete m[k];
      });
      return m;
    }
  }
  return obj;
};
